import org.apache.spark.sql.{DataFrame, SparkSession}

object Demo02SparkSQL01 {
  def main(args: Array[String]): Unit = {
    // 构建SparkSession环境
    val spark: SparkSession = SparkSession
      .builder()
      .appName("Demo02SparkSQL01")
      .master("local")
      .config("spark.sql.shuffle.partitions", "2")
      .getOrCreate()

    // DataFrame类似Pandas里的DF
    val stuDF: DataFrame = spark
      .read
      .format("csv")
      .option("sep", ",")
      .schema("id string,name String,age Int,gender String,clazz String")
      .load("data/students.txt")

    /**
     * SQL中常见的操作：
     * select 分组字段
     * ,分组后一般会使用聚合函数：count、max、min、sum、avg
     * ,条件函数、数值函数、字符串函数、日期函数、窗口函数
     * from tb
     * where 过滤
     * group by 分组
     * having 对分组后聚合的结果进行过滤
     * order by 指定字段进行排序
     * limit 限制返回的条数
     *
     * 多表之间还存在关联和联接的操作：
     * 关联：多表之间横向的拼接，需要指定关联字段的
     * 内连接：join、inner join
     * 外连接：outer join
     * 左外连接：left join、left outer join
     * 右外连接：right join、right outer join
     * 全外连接：full join、full outer join
     * 联接：多表纵向的拼接，需要表结构保持一致
     * union：会去重
     * union all：不会去重
     */

    // 1、通过SQL的方式进行处理

    // 将DF注册成表
    stuDF.createOrReplaceTempView("stu")

    // 通过SparkSession执行SQL
    // 统计班级人数并过滤出人数超过90的前三个班级
    spark.sql(
      """
        |select clazz
        |       ,count(*) as cnt
        |from stu
        |group by clazz
        |having cnt > 90
        |order by cnt desc
        |limit 3
        |""".stripMargin)
      .show()

    // 导入隐式转换以及函数包
    import spark.implicits._
    import org.apache.spark.sql.functions._
    // 2、DSL的方式
    stuDF
      .groupBy($"clazz")
      .agg(count("*") as "cnt")
      .where($"cnt" > 90)
      .orderBy($"cnt".desc)
      .limit(3)
      .show()

  }

}
